﻿#ifndef _CELLOBJECTPOOL_HPP_
#define _CELLOBJECTPOOL_HPP_
#include <stdlib.h>
#include <mutex>
#include <assert.h>

#ifdef ____DEBUG
#include <stdio.h>
#ifndef xPrintf
#define xPrintf(...) printf(__VA_ARGS__)
#endif // #ifndef xPrintf(...)
#else
#ifndef xPrintf
#define xPrintf(...)
#endif // #ifndef xPrintf(...)
#endif // #ifdef _DEBUG

/*
	模板参数：
		1. 对象池类型
		2. 对象池的大小
*/
template<typename Type, size_t nPoolSize>
class CELLLObjectPool final
{
public:
	CELLLObjectPool() : _pHeader(nullptr), _pBuf(nullptr)
	{
		InitPool();
	}
	~CELLLObjectPool()
	{
		if (_pBuf)
			delete[] _pBuf;
	}

	// 申请对象内存
	void* allocObjectMemory(size_t nSize)
	{
		std::lock_guard<std::mutex> lg(_mutex);
		NodeHeader* pReturn = nullptr;
		if (nullptr == _pHeader)
		{
			pReturn = (NodeHeader*)new char[sizeof(Type) * sizeof(NodeHeader)];
			pReturn->bPool = true;
			pReturn->nID = -1;
			pReturn->nRef = 1;
			pReturn->pNext = nullptr;
		}
		else
		{
			pReturn = _pHeader;
			_pHeader = _pHeader->pNext;
			assert(0 == pReturn->nRef);
			pReturn->nRef = 1;
		}
		xPrintf("allocObjectMemory: %lx, id=%d, size=%d", pReturn, pReturn->nID, nSize);
		return (char*)pReturn + sizeof(NodeHeader);
	}

	// 释放对象
	void freeObjectMemory(void* pMem)
	{
		// 内存前面是这块内存的信息，要得到信息就要偏移到内存的前面
		NodeHeader* pBlock = (NodeHeader*)((char*)pMem - sizeof(NodeHeader));
		xPrintf("freeObjectMemory: %lx, id=%d", pBlock, pBlock->nID);
		assert(1 == pBlock->nRef);
		if (pBlock->bPool)
		{// 在内存池中的直接放回内存池就行
			std::lock_guard<std::mutex> lg(_mutex);
			if (--pBlock->nRef != 0)
			{	
				return;
			}
			pBlock->pNext = _pHeader;
			_pHeader = pBlock;
		}
		else
		{// 在对象池外直接就是free
			if (--pBlock->nRef != 0)
			{
				return;
			}
			delete[] pBlock;
		}
	}
private:	
	// 初始化对象池
	void InitPool()
	{
		assert(nullptr == _pBuf);
		if (_pBuf)
			return;
		// 申请池的内存, 大小为 对象池类型大小 乘以 (对象池大小 加上 头部信息)
		size_t offSize = sizeof(Type) + sizeof(NodeHeader);
		_pBuf = new char[nPoolSize * offSize];
		// 初始化对象池
		_pHeader = (NodeHeader*)_pBuf;
		_pHeader->nID = 0;
		_pHeader->bPool = true;
		_pHeader->nRef = 0;
		_pHeader->pNext = nullptr;

		NodeHeader* pCur = _pHeader;
		NodeHeader* pNext = nullptr;
		for (size_t n = 1; n < nPoolSize; ++n)
		{
			pNext = (NodeHeader*)(_pBuf + offSize * n);
			pNext->nID = n;
			pNext->bPool = true;
			pNext->nRef = 0;
			pNext->pNext = nullptr;

			pCur->pNext = pNext;
			pCur = pNext;
		}
	}
protected:
	struct NodeHeader
	{
		// 下一块位置
		NodeHeader* pNext;
		// 内存块编号
		int nID;
		// 引用次数
		char nRef;
		// 是否在对象池中
		bool bPool;
	private:
		char c1;
		char c2;
	};
private:
	// 头部
	NodeHeader* _pHeader;
	// 对象池内存地址
	char* _pBuf;
	// 互斥量
	std::mutex _mutex;
};

// 以下是对外的接口类
template<typename Type, size_t nPoolSize>
class ObjectPoolBase
{
public:
	void* operator new(size_t size)
	{
		return ObjectPool().allocObjectMemory(size);
	}

	void operator delete(void* p)
	{
		ObjectPool().freeObjectMemory(p);
	}

	template<typename... Args>
	static Type* createObject(Args... args)
	{
		// 调用本类重载的new方法
		Type* obj = new Type(args...);
		return obj;
	}

	static void destoryObject(Type* obj)
	{
		// 调用本类重载的delete方法
		delete obj;
	}
private:
	typedef CELLLObjectPool<Type, nPoolSize> ClassTPool;
	static ClassTPool& ObjectPool()
	{// 单例对象池CELLLObjectPool对象
		static ClassTPool cPool;
		return cPool;
	}
};

#endif // #ifndef _CELLOBJECTPOOL_HPP_
